import 'package:flutter/material.dart';
import 'package:flutter_lui/flutter_lui.dart';
import 'package:flutter_lui/src/l_style.dart';

final double _itemHeight = lrpx(40);

// 滚轮
class LScrollWheel extends StatefulWidget {
  final String? value;
  final List<LScrollWheelItem> items;
  final double? itemHeight;
  final Function(LScrollWheelItem)? onChange;
  const LScrollWheel(
      {required this.items,
      this.itemHeight,
      this.value,
      this.onChange,
      Key? key})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => _LScrollWheel();
}

class _LScrollWheel extends State<LScrollWheel> {
  double itemHeight = _itemHeight;

  final ScrollController controller = ScrollController();

  /// 当前选中的项的索引
  int index = 0;

  /// 上次滚动的位置和本次滚动的位置 用于判断滚动方向
  double preOffset = -1;
  double currOffset = -1;

  bool hasAddControllerEvent = false;

  late List<LScrollWheelItem> items = [];
  @override
  void initState() {
    super.initState();
    init();
    itemHeight = _toSomeInt(widget.itemHeight ?? _itemHeight);
    WidgetsBinding.instance.addPostFrameCallback(initIndex);
  }

  @override
  void didUpdateWidget(LScrollWheel oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.items.map((i) => i.value).join(',') !=
        widget.items.map((i) => i.value).join(',')) {
      init();
    }
    initIndex('');
  }

  @override
  dispose() {
    super.dispose();
    controller.dispose();
  }

  init() {
    items = [
      ...widget.items
          .map((i) => LScrollWheelItem(
              label: i.label, value: i.value, otherValue: i.otherValue))
          .toList()
    ];

    items.insert(0, LScrollWheelItem(label: '', value: ''));
    items.insert(0, LScrollWheelItem(label: '', value: ''));
    items.add(LScrollWheelItem(label: '', value: ''));
    items.add(LScrollWheelItem(label: '', value: ''));
    for (var i = 0; i < items.length; i++) {
      items[i].index = i;
    }
  }

  initIndex(_) async {
    var tmp = items.map((e) => e.value).toList();
    var valueIndex =
        tmp.contains(widget.value) ? tmp.indexOf(widget.value!) : 2;
    if (valueIndex != index && valueIndex >= 0) {
      index = valueIndex;
      await controller.animateTo(_toSomeInt(itemHeight * (index - 2)),
          duration: const Duration(milliseconds: 200), curve: Curves.linear);
    }
    setState(() {});
    if (!hasAddControllerEvent) {
      hasAddControllerEvent = true;
      addControllerEvent();
    }
  }

  addControllerEvent() {
    controller.addListener(() {
      preOffset = currOffset;
      currOffset = _toSomeInt(controller.offset);
      controller.position.isScrollingNotifier
          .removeListener(handleCalcOffsetIndex);
      controller.position.isScrollingNotifier
          .addListener(handleCalcOffsetIndex);
    });
  }

  handleCalcOffsetIndex() {
    if (!controller.position.isScrollingNotifier.value) {
      // 滚动条外上方移出的高度
      var moveHideLength = _toSomeInt(controller.offset / itemHeight).toInt();
      var addIndex = 1;
      // 上方隐藏的高度越小 说明内容在向下移动
      if (preOffset > currOffset) {
        // 向下滚动 上方隐藏的渐渐出现
        if (controller.offset % itemHeight > itemHeight / 2) {
          // 向下移动的位置不到一项的一半 应该回去 让隐藏的高度变更大 +1
          addIndex = 1;
        } else {
          // 移动的位置超过一项的一半 应该下去 让隐藏的高度变更小 +0
          addIndex = 0;
        }
      } else if (preOffset < currOffset) {
        // 上方隐藏的高度越大 说明内容在向上滚动
        if (controller.offset % itemHeight < itemHeight / 2) {
          // 向上移动的位置不到一项的一半 应该回去 让隐藏的高度变小 +0
          addIndex = 0;
        } else {
          // 向上移动的位置超过一项的一半 应该上去 让隐藏的高度变小 +0
          addIndex = 1;
        }
      }
      if (_toSomeInt(currOffset / itemHeight) != moveHideLength) {
        controller.animateTo(_toSomeInt(moveHideLength + addIndex) * itemHeight,
            duration: const Duration(milliseconds: 50), curve: Curves.linear);
      } else {
        index = moveHideLength.toInt() + 2;
        print('move report index ${index - 2}');
        setState(() {});

        /// 处理完后移除监听事件 防止只移动0.00000002以内的事件，只移动这一点不会触发滚动但会触发滚动结束 会无限循环触发
        controller.position.isScrollingNotifier
            .removeListener(handleCalcOffsetIndex);
        // 第二次停止滚动后 向上传当前项
        if (widget.onChange != null) {
          var selectValue = items[index].copy();
          selectValue.index = items[index].index - 2;
          widget.onChange!(selectValue);
        }
      }
      preOffset = -1;
      currOffset = -1;
    }
  }

  @override
  Widget build(BuildContext context) {
    return LBox(
      height: itemHeight * 5,
      child: Stack(
        children: [
          Positioned(
            top: itemHeight * 2,
            left: 0,
            right: 0,
            child: LBox(
              height: itemHeight,
              gradient: const LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [
                    Color(0xffe5e5e5),
                    Color(0x55f5f5f5),
                    Color(0x55f5f5f5),
                    Color(0xffe5e5e5),
                  ],
                  stops: [
                    0,
                    0.2,
                    0.8,
                    1
                  ]),
            ),
          ),
          ScrollConfiguration(
            behavior: ListViewNoInkWillBehavior(),
            child: ListView(
              controller: controller,
              padding: EdgeInsets.zero,
              children: items
                  .map((item) => Opacity(
                        opacity: item.index == index
                            ? 1
                            : (item.index - 1 == index ||
                                    item.index + 1 == index)
                                ? 0.8
                                : 0.6,
                        child: LBox(
                          alignment: Alignment.center,
                          height: itemHeight,
                          padding: [0, lrpx(5)],
                          child: LText(
                            item.label,
                            fontSize: item.index == index
                                ? LStyle.fontSize + lrpx(2)
                                : (item.index - 1 == index ||
                                        item.index + 1 == index)
                                    ? LStyle.fontSize
                                    : LStyle.fontSize - lrpx(2),
                            fontWeight:
                                item.index == index ? FontWeight.bold : null,
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                          ),
                        ),
                      ))
                  .toList(),
            ),
          ),
        ],
      ),
    );
  }
}

class LScrollWheelItem {
  final String label;
  final String value;
  final dynamic otherValue;
  int index = 0;
  LScrollWheelItem({required this.label, required this.value, this.otherValue});

  copy() {
    return LScrollWheelItem(
      label: label,
      value: value,
      otherValue: otherValue,
    );
  }

  @override
  String toString() {
    return '{label: $label, value: $value, otherValue: $otherValue, index: $index}';
  }
}

class ListViewNoInkWillBehavior extends ScrollBehavior {
  // @override
  // Widget buildOverscrollIndicator(
  //     BuildContext context, Widget child, AxisDirection axisDirection) {
  //   return child;
  // }
}

/// 对所有参与计算offset的值进行四舍五入后保留一位小数
///
///  否则会有滚动不到位卡入死循环的情况
double _toSomeInt(num v) {
  return (v * 10).round() / 10;
}
